package com.fulihui.wgj.service.template;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.fulihui.common.builder.rpc.RpcResultBuilder;
import com.fulihui.common.enums.SendLogStatusEnum;
import com.fulihui.common.enums.TemplateLogTypeEnum;
import com.fulihui.common.enums.TemplateStatusEnum;
import com.fulihui.common.error.Errors;
import com.fulihui.common.error.InvokeServiceException;
import com.fulihui.common.result.rpc.BaseResult;
import com.fulihui.common.result.rpc.SimpleResult;
import com.fulihui.common.util.ConditionValidator;
import com.fulihui.common.util.JedisUtil;
import com.fulihui.weixinsdk.model.TemplateItem;
import com.fulihui.wgj.biz.SendTemplateMsgBiz;
import com.fulihui.wgj.biz.WxUserInfoBiz;
import com.fulihui.wgj.biz.common.util.TemplateRenderUtil;
import com.fulihui.wgj.dal.mybatis.domain.WxSendTemplateLog;
import com.fulihui.wgj.dal.mybatis.domain.WxTemplate;
import com.fulihui.wgj.dal.mybatis.repository.WxSendTemplateLogRepository;
import com.fulihui.wgj.dal.mybatis.repository.WxTemplateRepository;
import com.fulihui.wgj.facade.request.template.CalcSendCountRequest;
import com.fulihui.wgj.facade.service.template.SendTemplateMsgService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 模板消息发送
 *
 * @author wang_wx
 * @date 2018-07-27
 */
@Component
@Service(interfaceClass = SendTemplateMsgService.class, version = "1.0.0", timeout = 10000)
public class SendTemplateMsgServiceImpl implements SendTemplateMsgService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SendTemplateMsgServiceImpl.class);

    @Autowired
    private WxUserInfoBiz wxUserInfoBiz;

    @Autowired
    private WxTemplateRepository wxTemplateRepository;

    @Autowired
    private WxSendTemplateLogRepository wxSendTemplateLogRepository;

    @Autowired
    SendTemplateMsgBiz sendTemplateMsgBiz;

    @Autowired
    JedisUtil jedisUtil;

    @Override
    public SimpleResult<Long> countSendUser(CalcSendCountRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        Long count = wxUserInfoBiz.queryCount(request);
        LOGGER.info("电商预计发送人数 = {}", count);
        return RpcResultBuilder.succSimple(count);
    }

    @Override
    public BaseResult sendTemplateMsg(CalcSendCountRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);

        // 先判断模板是否已失效
        String templateId = request.getTemplateId();
        WxTemplate wxTemplateQuery = new WxTemplate();
        wxTemplateQuery.setTemplateId(templateId);
        WxTemplate wxTemplate = wxTemplateRepository.queryOne(wxTemplateQuery);
        if (Objects.isNull(wxTemplate) || TemplateStatusEnum.valid.getValue() != wxTemplate.getStatus().longValue()) {
            return RpcResultBuilder.fail(Errors.WxTemplateError.THIS_TEMPLATE_IS_NOT_VALID);
        }

        Long recordCount = wxUserInfoBiz.queryCount(request);
        LOGGER.info("sendTemplateMsg Calculation:{}", recordCount);
        if (0 >= recordCount) {
            // 推送人数为0 不允许推送
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.THE_CURRENT_APP_PUSHES_RECORD_EMPTY);
        }

        // 插入发送记录表
        WxSendTemplateLog templateLog = insertTemplateLog(request, TemplateLogTypeEnum.SHOP.getValue(), recordCount);
        if (Objects.isNull(templateLog) || Objects.isNull(templateLog.getId())) {
            LOGGER.info("SendTemplateMsgService sendTemplateMsg, templateLogId is null!!!");
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.TEMPLATE_LOG_RECORD_INSERT_ERROR);
        }

        if (!templateLog.getJobStatus() && Objects.isNull(templateLog.getJobTime())) {
            // 不是定时任务 立即发送
            LOGGER.info("SendTemplateMsgService, send shop now!");
            sendTemplateMsgBiz.sendTemplateMsg(request, templateLog);
        }
        return RpcResultBuilder.succ();
    }

    @Override
    public BaseResult sendTemplateMsgEdit(CalcSendCountRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        if (Objects.isNull(request.getRecordId())) {
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.ID_CANNOT_BE_EMPTY);
        }
        WxSendTemplateLog templateLogExist = wxSendTemplateLogRepository.queryById(request.getRecordId());
        if (Objects.isNull(templateLogExist)) {
            return RpcResultBuilder.fail(Errors.Commons.RECORD_NOT_EXISTS);
        }
        if (!templateLogExist.getJobStatus()) {
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.CANNOT_EDIT_NOT_JOB_LOG);
        }

        // 先判断模板是否已失效
        String templateId = request.getTemplateId();
        WxTemplate wxTemplateQuery = new WxTemplate();
        wxTemplateQuery.setTemplateId(templateId);
        WxTemplate wxTemplate = wxTemplateRepository.queryOne(wxTemplateQuery);
        if (Objects.isNull(wxTemplate) || TemplateStatusEnum.valid.getValue() != wxTemplate.getStatus().longValue()) {
            return RpcResultBuilder.fail(Errors.WxTemplateError.THIS_TEMPLATE_IS_NOT_VALID);
        }

        Long recordCount = wxUserInfoBiz.queryCount(request);
        LOGGER.info("sendTemplateMsgEdit Calculation:{}", recordCount);
        if (0 >= recordCount) {
            // 推送人数为0 不允许推送
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.THE_CURRENT_APP_PUSHES_RECORD_EMPTY);
        }

        // 更新发送记录表
        WxSendTemplateLog templateLog = updateTemplateLog(request, recordCount);
        if (Objects.isNull(templateLog) || Objects.isNull(templateLog.getId())) {
            LOGGER.info("SendTemplateMsgService sendTemplateMsgEdit, templateLogId is null!!!");
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.TEMPLATE_LOG_RECORD_INSERT_ERROR);
        }

        if (!templateLog.getJobStatus() && Objects.isNull(templateLog.getJobTime())) {
            // 不是定时任务 立即发送
            LOGGER.info("SendTemplateMsgService, send shop now!");
            sendTemplateMsgBiz.sendTemplateMsg(request, templateLog);
        }
        return RpcResultBuilder.succ();
    }

    @Override
    public BaseResult sendTemplateMsg4Job(CalcSendCountRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);
        Long recordId = request.getRecordId();
        if (Objects.isNull(recordId)) {
            LOGGER.warn("sendTemplateMsg4Job recordId is null , cannot send");
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.ID_CANNOT_BE_EMPTY);
        }
        WxSendTemplateLog templateLog = wxSendTemplateLogRepository.queryById(recordId);
        if (Objects.isNull(templateLog)) {
            LOGGER.warn("sendMassMsg4Job templateLog is null , cannot send");
            return RpcResultBuilder.fail(Errors.Commons.RECORD_NOT_EXISTS);
        }

        //查询用户的数量
        Long recordCount = 0L;
        Integer logType = templateLog.getTemplateLogType();
        if (TemplateLogTypeEnum.SHOP.getValue() == logType.intValue()) {
            recordCount = wxUserInfoBiz.queryCount(request);
        } else if (TemplateLogTypeEnum.GAME.getValue() == logType.intValue()) {
            recordCount = wxUserInfoBiz.queryCount4Game(request);
        }
        LOGGER.info("sendTemplateMsg4Job Calculation:{}", recordCount);
        // 更新记录状态
        WxSendTemplateLog templateLogUpdate = new WxSendTemplateLog();
        templateLogUpdate.setId(recordId);
        templateLogUpdate.setAllTotal(Math.toIntExact(recordCount));
        templateLogUpdate.setSendStartTime(new Date());
        templateLogUpdate.setSendStatus(SendLogStatusEnum.pushing.getCode());
        wxSendTemplateLogRepository.updateSelective(templateLogUpdate);
        // 发送
        if (TemplateLogTypeEnum.SHOP.getValue() == logType.intValue()) {
            sendTemplateMsgBiz.sendTemplateMsg(request, templateLog);
        } else if (TemplateLogTypeEnum.GAME.getValue() == logType.intValue()) {
            sendTemplateMsgBiz.sendTemplateMsg4Game(request, templateLog);
        }
        return RpcResultBuilder.succ();
    }

    /**
     * 插入消息发送记录表
     *
     * @param condition
     * @param logType     设置模板记录类型{@link com.fulihui.common.enums.TemplateLogTypeEnum}
     * @param recordCount
     * @return
     */
    private WxSendTemplateLog insertTemplateLog(CalcSendCountRequest condition, int logType, Long recordCount) {
        // 模板发送数据
        String templateContent = condition.getTemplateContent();
        Map<String, TemplateItem> data = JSON.parseObject(templateContent,
                new TypeReference<Map<String, TemplateItem>>() {
                });

        WxSendTemplateLog templateLog = new WxSendTemplateLog();
        templateLog.setTemplateLogType(logType);
        templateLog.setAppId(condition.getAppId());
        if (condition.getMiniApp() && StringUtils.isNotBlank(condition.getMiniAppUrl())
                && StringUtils.isNotBlank(condition.getMiniAppId())) {
            templateLog.setMiniAppId(condition.getMiniAppId());
            templateLog.setMiniProgramUrl(condition.getMiniAppUrl());
        }
        templateLog.setSendConditionDesc(condition.getSendConditionDesc());
        templateLog.setSendCondition(JSON.toJSONString(condition));
        templateLog.setJobStatus(condition.getCronTab());
        templateLog.setJobTime(Objects.isNull(condition.getJobTime()) ? null : condition.getJobTime());
        if (condition.getCronTab()) {
            templateLog.setSendStatus(SendLogStatusEnum.await.getCode());
        } else {
            templateLog.setSendStatus(SendLogStatusEnum.pushing.getCode());
        }

        templateLog.setAllTotal(Math.toIntExact(recordCount));
        templateLog.setFailTotal(0);
        templateLog.setSuccessTotal(0);
        templateLog.setSendStartTime(Objects.isNull(condition.getJobTime()) ? new Date() : condition.getJobTime());
        templateLog.setSendEndTime(null);
        templateLog.setTemplateContent(renderTemplate(data, condition.getTemplateId()));
        templateLog.setTemplateData(templateContent);
        templateLog.setJumpUrl(condition.getTemplateUrl());
        templateLog.setTemplateId(condition.getTemplateId());
        wxSendTemplateLogRepository.saveSelective(templateLog);
        LOGGER.info("insertTemplateLog:{}", templateLog);
        return templateLog;
    }

    /**
     * 消息发送记录表更新
     *
     * @param condition
     * @param recordCount
     * @return
     */
    private WxSendTemplateLog updateTemplateLog(CalcSendCountRequest condition, Long recordCount) {
        // 模板发送数据
        String templateContent = condition.getTemplateContent();
        Map<String, TemplateItem> data = JSON.parseObject(templateContent,
                new TypeReference<Map<String, TemplateItem>>() {
                });

        WxSendTemplateLog templateLog = new WxSendTemplateLog();
        templateLog.setId(condition.getRecordId());
        templateLog.setAppId(condition.getAppId());
        if (condition.getMiniApp() && StringUtils.isNotBlank(condition.getMiniAppUrl())
                && StringUtils.isNotBlank(condition.getMiniAppId())) {
            templateLog.setMiniAppId(condition.getMiniAppId());
            templateLog.setMiniProgramUrl(condition.getMiniAppUrl());
        }
        templateLog.setSendConditionDesc(condition.getSendConditionDesc());
        templateLog.setSendCondition(JSON.toJSONString(condition));
        templateLog.setJobStatus(condition.getCronTab());
        templateLog.setJobTime(Objects.isNull(condition.getJobTime()) ? null : condition.getJobTime());
        if (condition.getCronTab()) {
            templateLog.setSendStatus(SendLogStatusEnum.await.getCode());
        } else {
            templateLog.setSendStatus(SendLogStatusEnum.pushing.getCode());
        }

        templateLog.setAllTotal(Math.toIntExact(recordCount));
        templateLog.setFailTotal(0);
        templateLog.setSuccessTotal(0);
        templateLog.setSendStartTime(Objects.isNull(condition.getJobTime()) ? new Date() : condition.getJobTime());
        templateLog.setSendEndTime(null);
        templateLog.setTemplateContent(renderTemplate(data, condition.getTemplateId()));
        templateLog.setTemplateData(templateContent);
        templateLog.setJumpUrl(condition.getTemplateUrl());
        templateLog.setTemplateId(condition.getTemplateId());
        templateLog.setGmtModified(new Date());
        wxSendTemplateLogRepository.updateSelective(templateLog);
        LOGGER.info("updateTemplateLog:{}", templateLog);
        return templateLog;
    }

    @Override
    public SimpleResult<Long> countSendUser4Game(CalcSendCountRequest request) throws InvokeServiceException {
        Long count = wxUserInfoBiz.queryCount4Game(request);
        LOGGER.info("游戏预计发送人数 = {}", count);
        return RpcResultBuilder.succSimple(count);
    }

    @Override
    public BaseResult sendTemplateMsg4Game(CalcSendCountRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);

        // 先判断模板是否已失效
        String templateId = request.getTemplateId();
        WxTemplate wxTemplateQuery = new WxTemplate();
        wxTemplateQuery.setTemplateId(templateId);
        WxTemplate wxTemplate = wxTemplateRepository.queryOne(wxTemplateQuery);
        if (Objects.isNull(wxTemplate) || TemplateStatusEnum.valid.getValue() != wxTemplate.getStatus().longValue()) {
            return RpcResultBuilder.fail(Errors.WxTemplateError.THIS_TEMPLATE_IS_NOT_VALID);
        }

        Long recordCount = wxUserInfoBiz.queryCount4Game(request);
        LOGGER.info("Calculation:{}", recordCount);
        if (0 >= recordCount) {
            // 推送人数为0 不允许推送
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.THE_CURRENT_APP_PUSHES_RECORD_EMPTY);
        }

        // 插入发送记录表
        WxSendTemplateLog templateLog = insertTemplateLog(request, TemplateLogTypeEnum.GAME.getValue(), recordCount);
        if (Objects.isNull(templateLog) || Objects.isNull(templateLog.getId())) {
            LOGGER.info("SendTemplateMsgService sendTemplateMsg4Game, templateLogId is null!!!");
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.TEMPLATE_LOG_RECORD_INSERT_ERROR);
        }

        if (!templateLog.getJobStatus() && Objects.isNull(templateLog.getJobTime())) {
            // 不是定时任务 立即发送
            LOGGER.info("SendTemplateMsgService, send game now!");
            sendTemplateMsgBiz.sendTemplateMsg4Game(request, templateLog);
        }
        return RpcResultBuilder.succ();
    }

    @Override
    public BaseResult sendTemplateMsgEdit4Game(CalcSendCountRequest request) throws InvokeServiceException {
        ConditionValidator.validate(request);

        if (Objects.isNull(request.getRecordId())) {
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.ID_CANNOT_BE_EMPTY);
        }
        WxSendTemplateLog templateLogExist = wxSendTemplateLogRepository.queryById(request.getRecordId());
        if (Objects.isNull(templateLogExist)) {
            return RpcResultBuilder.fail(Errors.Commons.RECORD_NOT_EXISTS);
        }
        if (!templateLogExist.getJobStatus()) {
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.CANNOT_EDIT_NOT_JOB_LOG);
        }

        // 先判断模板是否已失效
        String templateId = request.getTemplateId();
        WxTemplate wxTemplateQuery = new WxTemplate();
        wxTemplateQuery.setTemplateId(templateId);
        WxTemplate wxTemplate = wxTemplateRepository.queryOne(wxTemplateQuery);
        if (Objects.isNull(wxTemplate) || TemplateStatusEnum.valid.getValue() != wxTemplate.getStatus().longValue()) {
            return RpcResultBuilder.fail(Errors.WxTemplateError.THIS_TEMPLATE_IS_NOT_VALID);
        }

        Long recordCount = wxUserInfoBiz.queryCount4Game(request);
        LOGGER.info("Calculation:{}", recordCount);
        if (0 >= recordCount) {
            // 推送人数为0 不允许推送
            return RpcResultBuilder.fail(Errors.WxTemplateLogError.THE_CURRENT_APP_PUSHES_RECORD_EMPTY);
        }

        // 更新发送记录表
        WxSendTemplateLog templateLog = updateTemplateLog(request, recordCount);

        if (!templateLog.getJobStatus() && Objects.isNull(templateLog.getJobTime())) {
            // 不是定时任务 立即发送
            LOGGER.info("SendTemplateMsgService, send game now!");
            sendTemplateMsgBiz.sendTemplateMsg4Game(request, templateLog);
        }
        return RpcResultBuilder.succ();
    }

    /**
     * 渲染模板内容
     *
     * @param data
     * @param templateId 模板ID
     * @return
     */
    private String renderTemplate(Map<String, TemplateItem> data, String templateId) {
        WxTemplate wxTemplateQuery = new WxTemplate();
        wxTemplateQuery.setTemplateId(templateId);
        List<WxTemplate> templateList = wxTemplateRepository.queryByWhere(wxTemplateQuery);
        if (!CollectionUtils.isEmpty(templateList)) {
            WxTemplate wxTemplate = templateList.get(0);
            if (Objects.nonNull(wxTemplate)) {
                return TemplateRenderUtil.render(data, wxTemplate);
            }
        }
        return null;
    }
}
